package com.quectel.switchcamera;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.legacy.app.FragmentCompat;
import androidx.preference.PreferenceManager;

import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Locale;

public class PreviewFragment extends Fragment implements FragmentCompat.OnRequestPermissionsResultCallback, View.OnClickListener {

    private final static String TAG = "PreviewFragment";
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    private String mParam1;
    private String mParam2;

    private static int PREVIEW_WIDTH_NOW = 1280;
    private static int PREVIEW_HEIGHT_NOW = 720;

    private static final int REQUEST_CAMERA_PERMISSION = 1;
    private String INITIAL_CAMERA_ID = "0";
    int realID = 0;
    private String currentCameraId;
    private int totalCameraNum;
    private CameraManager manager;

    private static final String[] CAMERA_PERMISSIONS = {
            Manifest.permission.CAMERA,
            Manifest.permission.RECORD_AUDIO
    };

    private CameraDevice mCameraDevice;
    private TextureView mTextureView;
    private Button switchButton, takePicButton, recordButton, settingsButton;
    private ImageView settingsImg;
    private TextView cameraNum;
    private TextView currentCameraID;
    private TextView recordDuration;
    private CaptureRequest.Builder mPreviewBuilder;
    private Handler mBackgroundHandler;
    private HandlerThread mBackgroundThread;
    private CameraCaptureSession mPreviewSession;

    private ImageReader rawImageReader;
    private File mFile;
    private Size largestRaw;
    private Surface previewSurface;
    private SparseIntArray ORIENTATIONS;
    private SparseIntArray INVERSE_ORIENTATIONS = new SparseIntArray();
    private int sensorOrientation;

    private MediaRecorder mMediaRecorder;
    private String mNextVideoAbsolutePath;
    private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90;
    private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270;
    private boolean mIsVideoRecording = false;
    private MyHandler mHandler;
    private long startTime;


    private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @RequiresApi(api = Build.VERSION_CODES.P)
        @Override
        public void onOpened(@NonNull CameraDevice cameraDevice) {
            Log.d(TAG, "onOpened");
            mCameraDevice = cameraDevice;
            setUpImageReader();
//            setUpCameraOutputs();
            startPreview();
//            configureTransform();
//            currentCameraID.setText(currentCameraId);
            switchButton.setText("切换" + currentCameraId + "/" + totalCameraNum);
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice cameraDevice) {

        }

        @Override
        public void onError(@NonNull CameraDevice cameraDevice, int i) {

        }
    };

    private TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surfaceTexture, int i, int i1) {
            Log.d(TAG, "onSurfaceTextureAvailable||realID =" + realID);
            openCamera(realID + "");
        }

        @Override
        public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surfaceTexture, int i, int i1) {

        }

        @Override
        public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surfaceTexture) {
            return false;
        }

        @Override
        public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surfaceTexture) {

        }
    };

    public static PreviewFragment getInstance() {
        return new PreviewFragment();
    }

    public static PreviewFragment newInstance(String param1, String param2) {
        PreviewFragment fragment = new PreviewFragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
        manager = (CameraManager) requireActivity().getSystemService(Context.CAMERA_SERVICE);
        mHandler = new MyHandler(this);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_preview, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mTextureView = view.findViewById(R.id.textureview);
        switchButton = view.findViewById(R.id.switchBtn);
        takePicButton = view.findViewById(R.id.takePicture);
        recordButton = view.findViewById(R.id.recordVideo);
        settingsButton = view.findViewById(R.id.settings);
        recordDuration = view.findViewById(R.id.record_duration);

        switchButton.setOnClickListener(this);
        takePicButton.setOnClickListener(this);
        recordButton.setOnClickListener(this);
        settingsButton.setOnClickListener(this);

        mFile = new File(requireActivity().
                getExternalFilesDir(null) + "/" + "image.raw");

        ORIENTATIONS = new SparseIntArray();
        ORIENTATIONS.append(Surface.ROTATION_0, 90);
        ORIENTATIONS.append(Surface.ROTATION_90, 0);
        ORIENTATIONS.append(Surface.ROTATION_180, 270);
        ORIENTATIONS.append(Surface.ROTATION_270, 180);

        INVERSE_ORIENTATIONS = new SparseIntArray();
        INVERSE_ORIENTATIONS.append(Surface.ROTATION_0, 270);
        INVERSE_ORIENTATIONS.append(Surface.ROTATION_90, 180);
        INVERSE_ORIENTATIONS.append(Surface.ROTATION_180, 90);
        INVERSE_ORIENTATIONS.append(Surface.ROTATION_270, 0);


        mMediaRecorder = new MediaRecorder();
    }

    @Override
    public void onResume() {
        super.onResume();
        String[] camerIdList = new String[0];
        try {
            camerIdList = manager.getCameraIdList();
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        int length = camerIdList.length;
        if (length > 0) {
            Log.d(TAG, "camerIdList.length =" + length);
//            cameraNum.setText(String.valueOf(length));
            totalCameraNum = length;
        }
        startBackgroundThread();
        setUpConfigations();
        if (mTextureView.isAvailable()) {
            openCamera(realID + "");
        } else {
            mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
        }

    }

    @Override
    public void onPause() {
        super.onPause();
        Log.d(TAG, "onPause");
        closeCamera();
    }

    @SuppressLint("MissingPermission")
    private void openCamera(String cameraId) {
        if (!hasPermissionsGranted(CAMERA_PERMISSIONS)) {
            Log.d(TAG, "hasPermissionsGranted");
            requestCameraPermission();
            return;
        }
        final Activity activity = getActivity();
        if (null == activity || activity.isFinishing()) {
            return;
        }
        currentCameraId = cameraId;
        Log.d(TAG, "openCamera||cameraId =" + cameraId);
//        configureTransform();

        try {
//            if ((ActivityCompat.checkSelfPermission(getActivity(),
//                    (Manifest.permission.CAMERA)) != PackageManager.PERMISSION_GRANTED)
//                    || (ActivityCompat.checkSelfPermission(getActivity(),
//                    (Manifest.permission.RECORD_AUDIO)) != PackageManager.PERMISSION_GRANTED)) {
//                return;
//            }
            manager.openCamera(cameraId, mStateCallback, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }

    private boolean hasPermissionsGranted(String[] permissions) {
        for (String permission : permissions) {
            if (ActivityCompat.checkSelfPermission(getActivity(), permission)
                    != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }


    private void requestCameraPermission() {
        if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
        } else {
            requestPermissions(CAMERA_PERMISSIONS, REQUEST_CAMERA_PERMISSION);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.P)
    private void startPreview() {
        SurfaceTexture mSurfaceTexture = mTextureView.getSurfaceTexture();
        assert mSurfaceTexture != null;
        Log.d(TAG, "startPreview||PREVIEW_WIDTH_NOW =" + PREVIEW_WIDTH_NOW);
        mSurfaceTexture.setDefaultBufferSize(PREVIEW_WIDTH_NOW, PREVIEW_HEIGHT_NOW);
        try {
            mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            previewSurface = new Surface(mSurfaceTexture);
            mPreviewBuilder.addTarget(previewSurface);

            Surface rawSurface = rawImageReader.getSurface();
//            mPreviewBuilder.addTarget(rawSurface);
//            Collections.singletonList(previewSurface)
//            Arrays.asList(previewSurface, rawSurface);
            mCameraDevice.createCaptureSession(Arrays.asList(previewSurface, rawSurface), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                    mPreviewSession = cameraCaptureSession;
                    updatePreview();
                    Log.d(TAG, "harrison||onConfigured");

                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {

                }
            }, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void updatePreview() {
        if (null == mCameraDevice) {
            return;
        }
        try {
            setUpCaptureRequestBuilder(mPreviewBuilder);
            HandlerThread thread = new HandlerThread("CameraPreview");
            thread.start();
            mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void setUpCaptureRequestBuilder(CaptureRequest.Builder builder) {
        builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
    }


    private void startBackgroundThread() {
        mBackgroundThread = new HandlerThread("CameraBackground");
        mBackgroundThread.start();
        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
    }

    private void stopBackgroundThread() {
        mBackgroundThread.quitSafely();
        try {
            mBackgroundThread.join();
            mBackgroundThread = null;
            mBackgroundHandler = null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void configureTransform() {
        Log.d(TAG, "configureTransform||PREVIEW_WIDTH_NOW =" + PREVIEW_WIDTH_NOW);
        int viewWidth = PREVIEW_WIDTH_NOW;
        int viewHeight = PREVIEW_HEIGHT_NOW;
        Activity activity = getActivity();

        assert activity != null;
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        Matrix matrix = new Matrix();
        RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
        RectF bufferRect = new RectF(0, 0, viewHeight, viewWidth);
        float centerX = viewRect.centerX();
        float centerY = viewRect.centerY();
        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
            float scale = Math.max(
                    (float) viewHeight / viewHeight,
                    (float) viewWidth / viewWidth);
            matrix.postScale(scale, scale, centerX, centerY);
            matrix.postRotate(90 * (rotation - 2), centerX, centerY);
        }
        mTextureView.setTransform(matrix);
    }


    private void closeCamera() {
        closePreviewSession();
//        stopBackgroundThread();
        if (null != mCameraDevice) {
            mCameraDevice.close();
            mCameraDevice = null;
        }
    }

    private void closePreviewSession() {
        if (mPreviewSession != null) {
            mPreviewSession.close();
            mPreviewSession = null;
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.switchBtn:
                closeCamera();
                Log.d(TAG, "currentCameraId =" + currentCameraId);
                realID = (Integer.parseInt(currentCameraId) + 1) % totalCameraNum;
                Log.d(TAG, "onClick||realID =" + realID);

                if (mTextureView.isAvailable()) {
                    Log.d(TAG, "available");
                    openCamera(realID + "");
                } else {
                    mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
                }

//            try {
//                threadTest();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
                break;
            case R.id.takePicture:
                capturePicture();
                break;
            case R.id.recordVideo:
                if (!mIsVideoRecording) {
                    startRecordingVideo();
                } else {
                    stopRecordingVideo();
                }
                break;
            case R.id.settings:
                Log.d(TAG, "settings clicked");
                Intent intent = new Intent(getActivity(), SettingsActivity.class);
                startActivity(intent);
                break;
        }
    }

    private void setUpImageReader() {
        Log.d(TAG, "setUpImageReader||mFile =" + mFile.getPath());
        rawImageReader = ImageReader.newInstance
                (PREVIEW_WIDTH_NOW, PREVIEW_HEIGHT_NOW, ImageFormat.JPEG, 1);
        rawImageReader.setOnImageAvailableListener(imageReader -> {
            Image image = imageReader.acquireLatestImage();
            new Thread(new ImageSaver(image, getActivity())).start();
//            image.close();
//            int format = image.getFormat();
//            Log.d(TAG, "onImageAvailable||format =" + format);
//            ByteBuffer buffer = image.getPlanes()[0].getBuffer();
//            byte[] bytes = new byte[buffer.remaining()];
//            buffer.get(bytes);
//            FileOutputStream output = null;
//            try {
//                if (!mFile.exists()) {
//                    mFile.createNewFile();
//                    Log.d(TAG, "createNewFile");
//                }
//                output = new FileOutputStream(mFile);
//                output.write(bytes);
//            } catch (IOException e) {
//                e.printStackTrace();
//            } finally {
//                image.close();
//            }
        }, mBackgroundHandler);
    }

    private void setUpCameraOutputs() {
        try {
            // Find a CameraDevice that supports RAW captures, and configure state.
//            for (String cameraId : manager.getCameraIdList()) {
            CameraCharacteristics characteristics
                    = manager.getCameraCharacteristics(INITIAL_CAMERA_ID);

            // We only use a camera that supports RAW in this sample.
            if (!contains(characteristics.get(
                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES),
                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
                return;
            }

            StreamConfigurationMap map = characteristics.get(
                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

            largestRaw = Collections.max(
                    Arrays.asList(map.getOutputSizes(ImageFormat.RAW_SENSOR)),
                    new CompareSizesByArea());
            Log.d(TAG, "raw.width =" + largestRaw.getWidth() + "||height =" + largestRaw.getHeight());
            setUpImageReader();
//                INITIAL_CAMERA_ID = cameraId;
//            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private static boolean contains(int[] modes, int mode) {
        if (modes == null) {
            return false;
        }
        for (int i : modes) {
            if (i == mode) {
                return true;
            }
        }
        return false;
    }

    static class CompareSizesByArea implements Comparator<Size> {

        @Override
        public int compare(Size lhs, Size rhs) {
            // We cast here to ensure the multiplications won't overflow
            return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
                    (long) rhs.getWidth() * rhs.getHeight());
        }

    }

    private void threadTest() throws InterruptedException {
        Log.d(TAG, "threadTest");
        Thread thread1 = new Thread(() -> {
            Log.d(TAG, "threadTest1 started");
        });
        Thread thread2 = new Thread(() -> {
            Log.d(TAG, "threadTest2 started");
        });
        Thread thread3 = new Thread(() -> {
            Log.d(TAG, "threadTest3 started");
        });

        thread1.start();
        thread1.join();
        thread2.start();
        thread2.join();
        thread3.start();
        thread3.join();
//        switchButton.setOnClickListener(view -> threadTest());
    }

    private void setUpConfigations() {
        if (null != getActivity()) {
            SharedPreferences mPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
            String resolution = mPref.getString("resolution", "720p");
            boolean gps = mPref.getBoolean("gps", false);
            Log.d(TAG, "resolution =" + resolution + "||gps =" + gps);

            assert resolution != null;
            switch (resolution) {
                case "720p":
                    PREVIEW_WIDTH_NOW = 1280;
                    PREVIEW_HEIGHT_NOW = 720;
                    break;
                case "1080p":
                    PREVIEW_WIDTH_NOW = 1920;
                    PREVIEW_HEIGHT_NOW = 1080;
                    break;
                case "4k":
                    PREVIEW_WIDTH_NOW = 3840;
                    PREVIEW_HEIGHT_NOW = 2160;
                    break;
            }
        }

    }

    private void capturePicture() {
        Log.d(TAG, "capturePicture");
        try {
            //首先我们创建请求拍照的CaptureRequest
            final CaptureRequest.Builder mCaptureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            //获取屏幕方向
            int rotation = requireActivity().getWindowManager().getDefaultDisplay().getRotation();
            CameraCharacteristics characteristics
                    = manager.getCameraCharacteristics(realID + "");
            sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);

            mCaptureBuilder.addTarget(previewSurface);
            mCaptureBuilder.addTarget(rawImageReader.getSurface());

            Log.d(TAG, "rotation =" + rotation);
            //设置拍照方向
            mCaptureBuilder.set(CaptureRequest.JPEG_ORIENTATION,
                    (ORIENTATIONS.get(rotation) + sensorOrientation + 270) % 360);

            //停止预览
            mPreviewSession.stopRepeating();

            //开始拍照，然后回调上面的接口重启预览，因为mCaptureBuilder设置ImageReader作为target，所以会自动回调ImageReader的onImageAvailable()方法保存图片
            CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {

                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                    updatePreview();
                }
            };

            mPreviewSession.capture(mCaptureBuilder.build(), captureCallback, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private String getVideoFilePath(Context context) {
        final File dir = context.getExternalFilesDir(null);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
        Date date = new Date(System.currentTimeMillis());
        String formatString = simpleDateFormat.format(date);
        return (dir == null ? "" : (dir.getAbsolutePath() + "/"))
                + formatString + ".mp4";
    }

    private void startRecordingVideo() {
        if (null == mCameraDevice || !mTextureView.isAvailable()) {
            return;
        }
        Log.d(TAG, "startRecordingVideo");
        startTime = SystemClock.elapsedRealtime();
        mHandler.sendEmptyMessage(0x01);
        try {
            closePreviewSession();

            setUpMediaRecorder();
            SurfaceTexture texture = mTextureView.getSurfaceTexture();
            assert texture != null;
            texture.setDefaultBufferSize(PREVIEW_WIDTH_NOW, PREVIEW_HEIGHT_NOW);
            mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
            List<Surface> surfaces = new ArrayList<>();

            // Set up Surface for the camera preview
            Surface previewSurface = new Surface(texture);
            surfaces.add(previewSurface);
            mPreviewBuilder.addTarget(previewSurface);

            // Set up Surface for the MediaRecorder
            Surface recorderSurface = mMediaRecorder.getSurface();
            surfaces.add(recorderSurface);
            mPreviewBuilder.addTarget(recorderSurface);

//            Surface imageReaderSurface = mImageReader.getSurface();
////CaptureRequest添加imageReaderSurface，不加的话就会导致ImageReader的onImageAvailable()方法不会回调
//            surfaces.add(imageReaderSurface);
//            mPreviewBuilder.addTarget(imageReaderSurface);

            // Start a capture session
            // Once the session starts, we can update the UI and start recording
            mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {

                @Override
                public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                    mPreviewSession = cameraCaptureSession;
                    updatePreview();
                    requireActivity().runOnUiThread(() -> {
                        // UI
                        recordButton.setText("停止录像");
                        mIsVideoRecording = true;
                        mMediaRecorder.start();
                    });
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                    Activity activity = getActivity();
                    if (null != activity) {
                        Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
                    }
                }
            }, mBackgroundHandler);
        } catch (CameraAccessException | IOException e) {
            e.printStackTrace();
        }

    }

    @RequiresApi(api = Build.VERSION_CODES.P)
    private void stopRecordingVideo() {
        mIsVideoRecording = false;
        recordButton.setText("开始录像");
        // Stop recording
        mMediaRecorder.stop();
        mMediaRecorder.reset();

        Activity activity = getActivity();
        if (null != activity) {
            Toast.makeText(activity, "Video saved: " + mNextVideoAbsolutePath,
                    Toast.LENGTH_SHORT).show();
            Log.d(TAG, "Video saved: " + mNextVideoAbsolutePath);
        }
        mNextVideoAbsolutePath = null;
//        updatePreview();
        startPreview();
    }

    private void setUpMediaRecorder() throws IOException {
        final Activity activity = getActivity();
        if (null == activity) {
            return;
        }
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);

        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        if (mNextVideoAbsolutePath == null || mNextVideoAbsolutePath.isEmpty()) {
            mNextVideoAbsolutePath = getVideoFilePath(getActivity());
            Log.d(TAG, "mNextVideoAbsolutePath =" + mNextVideoAbsolutePath);
        }
        mMediaRecorder.setOutputFile(mNextVideoAbsolutePath);
        mMediaRecorder.setVideoEncodingBitRate(10000000);
        mMediaRecorder.setVideoFrameRate(30);
        // mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
        mMediaRecorder.setVideoSize(PREVIEW_WIDTH_NOW, PREVIEW_HEIGHT_NOW);

        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        switch (sensorOrientation) {
            case SENSOR_ORIENTATION_DEFAULT_DEGREES:
                mMediaRecorder.setOrientationHint(ORIENTATIONS.get(rotation));
                break;
            case SENSOR_ORIENTATION_INVERSE_DEGREES:
                mMediaRecorder.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation));
                break;
        }
        mMediaRecorder.prepare();
    }


    public static class ImageSaver implements Runnable {
        private Image mImage;
        private File mImageFile;
        private Context mContext;

        public ImageSaver(Image image, Context context) {
            mImage = image;
            mContext = context;
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
            String dateStr = sdf.format(new Date());
            mImageFile = new File(mContext.getExternalFilesDir(null) +
                    "/cameraSwitch_" + dateStr + ".jpg");
            Log.d(TAG, "ImageSaver||mImageFile =" + mImageFile.getPath());
        }

        @Override
        public void run() {
            ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
            byte[] data = new byte[buffer.remaining()];
            buffer.get(data);

            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(mImageFile);
                fos.write(data, 0, data.length);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                mImageFile = null;
                mImage.close();
                if (fos != null) {
                    try {
                        fos.close();
                        fos = null;
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }


    private static class MyHandler extends Handler {
        private WeakReference<PreviewFragment> fragment;
        private final int REFRESH_DURATION = 0x01;

        private MyHandler(PreviewFragment previewFragment) {
            fragment = new WeakReference<>(previewFragment);
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            if (null == fragment.get()) {
                return;
            }
            switch (msg.what) {
                case REFRESH_DURATION:
                    int time = (int) ((SystemClock.elapsedRealtime() - fragment.get().startTime) / 1000);
                    String hh = new DecimalFormat("00").format(time / 3600);
                    String mm = new DecimalFormat("00").format(time % 3600 / 60);
                    String ss = new DecimalFormat("00").format(time % 60);
                    fragment.get().recordDuration.setText(hh + ":" + mm + ":" + ss);
                    sendEmptyMessageDelayed(REFRESH_DURATION, 1000);
                    break;
                default:
                    break;
            }
        }
    }
}